package com.metrology.app.dao.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;

import com.metrology.app.dao.DomainObjectDao;
import com.metrology.app.dao.common.CommonClientDaoSupport;
import com.metrology.app.domain.DomainObject;
import com.metrology.common.session.WebUserUtil;

public class DomainObjectDaoImpl<T> extends CommonClientDaoSupport 
	implements	DomainObjectDao<T> {
	
	private static Logger LOG = Logger.getLogger(DomainObjectDaoImpl.class);
	
	protected ApplicationContext context;
	
	protected static Map<String, Boolean> cacheExistsMap = new HashMap<String, Boolean>();
	
	@Override
	public Long getSequenceId() {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("sequenceTable", "Dp_Sequence");
		getSqlSession().insert("DomainObject.get_sequence_nextval", param);
		Long result = (Long)param.get("result");
		if(result == -1){
			String message = "When get sequence id from [get_sequence_nextval], error happened";
			LOG.error(message);
			throw new RuntimeException(message);
		}
		return result;
	}

	public void saveOrUpdate(T domainT) {
		DomainObject domain = (DomainObject)domainT;
		if(domain.getUuid() == null || domain.isNewWithId()){
			if(!domain.isNewWithId() && !domain.isAutoGenId()){
				domain.setId(this.getSequenceId());
			}
			
			if(!domain.isUpdated()){
				domain.setInsertOperation(WebUserUtil.getUserId());
			}
			
			super._insert(domain);
			
		}else{
			if(!domain.isUpdated()){
				domain.setUpdateOperation(WebUserUtil.getUserId());
			}
			
			super._update(domain);
			
		}
		domain.setUpdated(false);
	}
	
	@Override
	public void updateWithoutFlush(T domainT) {
		DomainObject domain = (DomainObject)domainT;
		if(!domain.isUpdated()){
			domain.setUpdateOperation(WebUserUtil.getUserId());
		}
		getSqlSession().update(
				getStatementId(domainT.getClass(),
						CommonClientDaoSupport.POSTFIX_UPDATE_WITHOUT_FLUSH), domainT);
	}


	@Override
	public void update(String updateSql, T obj) {
		getSqlSession().update(updateSql, obj);
	}
	
	@Override
	public void insert(String insertSql, T obj) {
		getSqlSession().insert(insertSql, obj);
	}

	public void delete(T domainT) {
		DomainObject domain = (DomainObject)domainT;
		if(!domain.isUpdated()){
			domain.setDeleteOperation(WebUserUtil.getUserId());
		}
		super._update(domain);
		domain.setUpdated(false);
	}
	
	public void delete(Class<T> domainClass, Long uuid) {
		super._rogicDelete(domainClass, uuid);
	}
	
	public void remove(Class<T> domainClass, Long uuid) {
		super._remove(domainClass, uuid);
	}
	
	public void remove(T domain) {
		DomainObject domainObj = (DomainObject)domain;
		super._remove(domain.getClass(), domainObj.getId());
	}

	@Override
	public void removeAll(Class<?> clazz) {
		super.removeAll(clazz);
	}


	public List<T> findAll(Class<T> domainClass) {
		List<T> allDomains = null;
		allDomains = _findAll(domainClass);
		if(allDomains == null || allDomains.isEmpty() ){
			return null;
		}
		return allDomains;
	}
	
	@Override
	public List<T> findByQueryMap(Map<String, Object> params, String queryName) {
		return super._findAll(params, queryName);
	}

	@SuppressWarnings("unchecked")
	public T load(Class<T> domainClass, Long id) {
		Object domainObject = null;
		if(domainObject == null){
			domainObject = _load(domainClass, id);
			DomainObject domain = (DomainObject) domainObject;
			if(domain == null){
				return null;
			}
		}
		return (T)domainObject;
	}

	public void batchSaveOrUpdate(Collection<T> objs) {
		if (objs == null || objs.isEmpty()) {
			return;
		}
		List<Serializable> keys = null;
		DomainObject domain = null;
		Long userId = WebUserUtil.getUserId();
		SqlSession session = super.getSqlSession();
		for (T domainT : objs) {
			domain = (DomainObject) domainT;
			if (domain.getUuid() == null || domain.isNewWithId()) {
				if (!domain.isNewWithId() && !domain.isAutoGenId()) {
					domain.setId(this.getSequenceId());
				}

				if (!domain.isUpdated()) {
					domain.setInsertOperation(userId);
				}

				session.insert(getStatementId(domain.getClass(),
						CommonClientDaoSupport.POSTFIX_INSERT), domain);
			} else {
				if (keys == null) {
					keys = new ArrayList<Serializable>();
				}
				domain.setUpdateOperation(userId);
				session.update(getStatementId(domain.getClass(),
						CommonClientDaoSupport.POSTFIX_UPDATE), domain);
			}
			domain.setUpdated(false);
		}
	}
	
	@Override
	public void batchDeleteObjs(Collection<T> objs) {
		if (objs == null || objs.isEmpty()) {
			return;
		}
		DomainObject domain = null;
		Long userId = WebUserUtil.getUserId();
		SqlSession session = super.getSqlSession();
		for (T domainT : objs) {
			domain = (DomainObject) domainT;
			if(!domain.isUpdated()){
				domain.setDeleteOperation(userId);
			}
			session.update(getStatementId(domain.getClass(),CommonClientDaoSupport.POSTFIX_UPDATE), domain);
			domain.setUpdated(false);
		}
	}
	
	public void batchUpdateBySqlId(Collection<T> objs, String sqlId) {
		if (objs == null || objs.isEmpty()) {
			return;
		}
		SqlSession session = super.getSqlSession();
		DomainObject domain = null;
		Long userId = WebUserUtil.getUserId();
		for (T domainT : objs) {
			domain = (DomainObject) domainT;
			domain.setUpdateOperation(userId);
			session.update(getStatementId(domain.getClass(),sqlId), domain);
		}
	}

	public void removeByForeignKey(Class<T> domainClass, Long fkey) {
		super._removeByFKey(domainClass, fkey);	
	}

	public void deleteByForeignKey(Class<T> domainClass, Long fkey) {
		super._rogicDeleteByFKey(domainClass, fkey);
	}

	@Override
	public List<T> findByQueryName(String queryName) {
		return this.findByQueryMap(null, queryName);
	}

}
